package com.xr.file.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xr.common.utils.FileUtil;
import com.xr.common.utils.XrObjectUtil;
import com.xr.file.mapper.SysUploadTaskMapper;
import com.xr.file.model.dto.FileDto;
import com.xr.file.model.entity.SysUploadTask;
import com.xr.file.service.IFileService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.xr.common.axios.AxiosEnum;
import com.xr.common.axios.AxiosResult;
import com.xr.common.exception.MyCustomException;
import com.xr.common.utils.ParallelStreamUtil;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 分片上传-分片任务记录
 *
 * @author fzh
 * @email e_341877120_mail@163.com
 * @date 2023-04-01 08:40:57
 */
@Service("iFileService")
@Transactional
public class FileServiceImpl extends ServiceImpl<SysUploadTaskMapper, SysUploadTask> implements IFileService {

	@Resource
	private AmazonS3 amazonS3Client;

	/**
	 * 根据条件查询列表
	 * @param fileDto
	 * @return
	 */
	@Override
	public AxiosResult selectList(FileDto fileDto) {
		LambdaQueryWrapper<SysUploadTask> lqw;
		if (XrObjectUtil.checkOfAllNull(fileDto)) {
			lqw = null;
		}
		else {
			lqw = new LambdaQueryWrapper<>();
		}
		List<SysUploadTask> fileList = baseMapper.selectList(lqw);
		boolean flag = ObjectUtils.isNotEmpty(fileList);
		return flag ? AxiosResult.selectSuccess(fileList) : AxiosResult.selectError();
	}

	/**
	 * 根据条件分页查询
	 * @param currentPage
	 * @param pageSize
	 * @param fileDto
	 * @return
	 */
	@Override
	public AxiosResult selectPage(int currentPage, int pageSize, FileDto fileDto) {
		IPage<SysUploadTask> iPage = new Page(currentPage, pageSize);
		LambdaQueryWrapper<SysUploadTask> lqw;
		if (XrObjectUtil.checkOfAllNull(fileDto)) {
			lqw = null;
		}
		else {
			lqw = new LambdaQueryWrapper<>();
			lqw.like(StringUtils.isNotBlank(fileDto.getBucketName()), SysUploadTask::getBucketName,
					fileDto.getBucketName()).like(StringUtils.isNotBlank(fileDto.getFileName()),
							SysUploadTask::getFileName, fileDto.getFileName());
		}
		iPage = page(iPage, lqw);
		boolean flag = ObjectUtils.isNotEmpty(iPage);
		return flag ? AxiosResult.selectSuccess(iPage) : AxiosResult.selectError();
	}

	/**
	 * 根据id查询单个
	 * @param id
	 * @return
	 */
	@Override
	public AxiosResult selectOneById(Long id) {
		if (ObjectUtils.isNotEmpty(id)) {
			SysUploadTask file = getById(id);
			boolean flag = ObjectUtils.isNotEmpty(file);
			return flag ? AxiosResult.selectSuccess(file) : AxiosResult.selectError();
		}
		throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
	}

	/**
	 * 新增
	 * @param fileDto
	 * @return
	 */
	@Override
	public AxiosResult insert(FileDto fileDto) {
		if (ObjectUtils.isNotEmpty(fileDto)) {
			boolean flag = save(fileDto);
			return flag ? AxiosResult.insertSuccess() : AxiosResult.insertError();
		}
		throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
	}

	/**
	 * 更新
	 * @param fileDto
	 * @return
	 */
	@Override
	public AxiosResult update(FileDto fileDto) {
		if (ObjectUtils.isNotEmpty(fileDto)) {
			boolean flag = updateById(fileDto);
			return flag ? AxiosResult.updateSuccess() : AxiosResult.updateError();
		}
		throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
	}

	/**
	 * 根据id删除单个
	 * @param id
	 * @return
	 */
	@Override
	public AxiosResult delete(Long id) {
		if (ObjectUtils.isNotEmpty(id)) {
			SysUploadTask file = getById(id);
			String bucketName = file.getBucketName();
			String objectKey = file.getObjectKey();
			// 删除文件
			try {
				amazonS3Client.deleteObject(bucketName, objectKey);
			}
			catch (SdkClientException e) {
				log.error(AxiosEnum.FILE_REMOVE_ERROR.getMsg());
				e.printStackTrace();
			}
			// 删除对应数据库记录
			boolean flag = removeById(id);
			return flag ? AxiosResult.deleteSuccess() : AxiosResult.deleteError();
		}
		throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
	}

	/**
	 * 根据id集合批量删除
	 * @param idList
	 * @return
	 */
	@Override
	public AxiosResult deleteBatch(List<Long> idList) {
		if (ObjectUtils.isEmpty(idList) || idList.size() == 0) {
			throw new MyCustomException(AxiosEnum.PARAMETER_ERROR);
		}
		// 定义原子性标识变量flag
		AtomicBoolean flag = new AtomicBoolean(false);
		idList.forEach((id) -> {
			SysUploadTask file = getById(id);
			String bucketName = file.getBucketName();
			String objectKey = file.getObjectKey();
			// 删除文件
			try {
				amazonS3Client.deleteObject(bucketName, objectKey);
			}
			catch (SdkClientException e) {
				log.error(AxiosEnum.FILE_REMOVE_ERROR.getMsg());
				e.printStackTrace();
			}
			// 删除对应数据库记录
			flag.set(removeById(id));
		});
		return flag.get() ? AxiosResult.deleteSuccess() : AxiosResult.deleteError();
	}

	/**
	 * 导入文件
	 * @param file
	 * @return
	 */
	@Override
	public AxiosResult importFile(MultipartFile file) {
		boolean flag = false;
		try {
			InputStream inputStream = file.getInputStream();
			ExcelReader er = ExcelUtil.getReader(inputStream);
			List<SysUploadTask> fileList = er.readAll(SysUploadTask.class);
			flag = ParallelStreamUtil.insertBatchOfLarge(fileList, baseMapper::insertBatch);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return flag ? AxiosResult.success(AxiosEnum.IMPORT_SUCCESS) : AxiosResult.error(AxiosEnum.IMPORT_ERROR);
	}

	/**
	 * 导出文件
	 * @param response
	 */
	@Override
	public void exportFile(HttpServletResponse response) {
		try {
			List<SysUploadTask> fileList = list();
			ExcelWriter ew = ExcelUtil.getWriter(true);
			ew.setOnlyAlias(true);
			ew.write(fileList);
			response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
			String fileName = URLEncoder.encode("Excel导出表", "UTF-8");
			response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
			ServletOutputStream sos = response.getOutputStream();
			ew.flush(sos, true);
			sos.close();
			IoUtil.close(sos);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 下载文件到本地
	 * @param url
	 * @param response
	 */
	public void downloadFile(String url, HttpServletResponse response) {
		try {
			// 从url中截取出文件名
			String fileName = url.substring(url.lastIndexOf("/") + 1);
			ServletOutputStream sos = response.getOutputStream();
			response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
			response.setContentType("application/octet-stream");
			// 通过文件远程url读取文件的字节流
			sos.write(Objects.requireNonNull(FileUtil.getFileStream(url)));
			sos.flush();
			sos.close();
		}
		catch (IOException e) {
			log.error(AxiosEnum.DOWNLOAD_ERROR.getMsg());
			e.printStackTrace();
		}
	}

}
